// 《围棋》作者版权所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// go:构建amd64 | arm64 | mips64 | mips64 | mips64le | ppc64 | ppc64le | riscv64 | s390x | wasm 
// /+构建amd64 arm64 mips64 mips64le ppc64 ppc64le riscv64 s390x wasm 

package runtime

import "unsafe"

const (
	// 表示虚拟地址所需的位数。
	// 
	// 有关
	// 各种体系结构上的地址空间大小表，请参阅HeapArbits。48位对于除s390x之外的所有
	// 体系结构都足够了。
	// 
	// 在AMD64上，虚拟地址是扩展到64的48位（或57位）数字符号。
	// 我们将地址左移16，以消除符号扩展部分，并使
	// 在底部的房间中进行计数。
	// 
	// 在s390x上，虚拟地址为64位。对于这一点，我们无能为力，所以我们只希望内核不会达到非常高的地址，如果达到了，就会出现恐慌。
	addrBits = 48

	// 除了从顶部获取的16位之外，我们还可以从
	// 底部获取3位，因为节点必须是指针对齐的，总共给出19位
	// 的计数。
	cntBits = 64 - addrBits + 3

	// 在AIX上，64位地址分为36位段号和28位
	// 段偏移量。范围为0x0A0000000-0x0AFFFFFF（LSA）
	// 的段号可用于mmap。
	// 我们假设所有lfnode地址都来自使用mmap分配的内存。
	// 我们使用一位来区分这两个范围。
	aixAddrBits = 57
	aixCntBits  = 64 - aixAddrBits + 3
)

func lfstackPack(node *lfnode, cnt uintptr) uint64 {
	if GOARCH == "ppc64" && GOOS == "aix" {
		return uint64(uintptr(unsafe.Pointer(node)))<<(64-aixAddrBits) | uint64(cnt&(1<<aixCntBits-1))
	}
	return uint64(uintptr(unsafe.Pointer(node)))<<(64-addrBits) | uint64(cnt&(1<<cntBits-1))
}

func lfstackUnpack(val uint64) *lfnode {
	if GOARCH == "amd64" {
		// amd64系统可以将堆栈放置在VA孔上方，因此我们需要在解包前签署extend 
		// val。
		return (*lfnode)(unsafe.Pointer(uintptr(int64(val) >> cntBits << 3)))
	}
	if GOARCH == "ppc64" && GOOS == "aix" {
		return (*lfnode)(unsafe.Pointer(uintptr((val >> aixCntBits << 3) | 0xa<<56)))
	}
	return (*lfnode)(unsafe.Pointer(uintptr(val >> cntBits << 3)))
}
